package container

// ProceedingJoinPoint 是环绕切面调用点
type ProceedingJoinPoint func() (interface{}, error)

// Aspect 切面接口（Before/After 可选，Around 可选）
type Aspect interface {
	Before(method string, args []interface{})
	After(method string, args []interface{}, result interface{}, err error)
	// Around 不强制必须实现
	Around(method string, args []interface{}, proceed ProceedingJoinPoint) (interface{}, error)
}

// ApplyBefore 平铺执行所有 Before
func ApplyBefore(aspects []Aspect, method string, args []interface{}) {
	for _, asp := range aspects {
		asp.Before(method, args)
	}
}

// ApplyAfter 平铺执行所有 After
func ApplyAfter(aspects []Aspect, method string, args []interface{}, result interface{}, err error) {
	for _, asp := range aspects {
		asp.After(method, args, result, err)
	}
}

// CallWithAround 按责任链模式执行 Around
// idx 当前切面下标，proceed 是下一个环节（可能是方法本身或下一个切面）
func CallWithAround(aspects []Aspect, idx int, method string, args []interface{}, proceed ProceedingJoinPoint) (interface{}, error) {
	if idx >= len(aspects) {
		return proceed()
	}

	// 尝试断言是否实现了 Around
	if around, ok := aspects[idx].(interface {
		Around(method string, args []interface{}, proceed ProceedingJoinPoint) (interface{}, error)
	}); ok {
		return around.Around(method, args, func() (interface{}, error) {
			return CallWithAround(aspects, idx+1, method, args, proceed)
		})
	}

	// 不支持 Around 的，默认用 Before/After 包裹
	aspects[idx].Before(method, args)
	res, err := CallWithAround(aspects, idx+1, method, args, proceed)
	aspects[idx].After(method, args, res, err)
	return res, err
}
